#include "../src/parser/sql_parser.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

// Test helper functions
static void print_expression(expression_t* expr, int indent);
static void print_statement(statement_t* stmt);
static void print_indent(int indent);

static void print_indent(int indent) {
    for (int i = 0; i < indent; i++) {
        printf("  ");
    }
}

static void print_expression(expression_t* expr, int indent) {
    if (!expr) {
        print_indent(indent);
        printf("NULL\n");
        return;
    }
    
    print_indent(indent);
    printf("%s:\n", expr_type_to_string(expr->type));
    
    switch (expr->type) {
        case EXPR_COLUMN:
            print_indent(indent + 1);
            if (expr->data.column.table_name) {
                printf("table: %s\n", expr->data.column.table_name);
                print_indent(indent + 1);
            }
            printf("column: %s\n", expr->data.column.column_name ? expr->data.column.column_name : "NULL");
            break;
            
        case EXPR_LITERAL:
            print_indent(indent + 1);
            printf("value: %s\n", expr->data.literal.value ? expr->data.literal.value : "NULL");
            break;
            
        case EXPR_BINARY_OP:
            print_indent(indent + 1);
            printf("operator: %s\n", token_type_to_string(expr->data.binary_op.operator));
            print_indent(indent + 1);
            printf("left:\n");
            print_expression(expr->data.binary_op.left, indent + 2);
            print_indent(indent + 1);
            printf("right:\n");
            print_expression(expr->data.binary_op.right, indent + 2);
            break;
            
        case EXPR_UNARY_OP:
            print_indent(indent + 1);
            printf("operator: %s\n", token_type_to_string(expr->data.unary_op.operator));
            print_indent(indent + 1);
            printf("operand:\n");
            print_expression(expr->data.unary_op.operand, indent + 2);
            break;
            
        case EXPR_STAR:
            print_indent(indent + 1);
            printf("*\n");
            break;
            
        case EXPR_LIST:
            print_indent(indent + 1);
            printf("count: %u\n", expr->data.list.count);
            for (uint32_t i = 0; i < expr->data.list.count; i++) {
                print_indent(indent + 1);
                printf("item[%u]:\n", i);
                print_expression(expr->data.list.expressions[i], indent + 2);
            }
            break;
            
        case EXPR_FUNCTION_CALL:
            print_indent(indent + 1);
            printf("Function: %s\n", 
                   expr->data.function_call.function_name ? expr->data.function_call.function_name : "NULL");
            print_indent(indent + 1);
            printf("Arguments (%u):\n", expr->data.function_call.arg_count);
            for (uint32_t i = 0; i < expr->data.function_call.arg_count; i++) {
                print_indent(indent + 1);
                printf("Arg[%u]:\n", i);
                print_expression(expr->data.function_call.args[i], indent + 2);
            }
            break;
            
        default:
            print_indent(indent + 1);
            printf("Unknown expression type\n");
            break;
    }
}

static void print_statement(statement_t* stmt) {
    if (!stmt) {
        printf("NULL statement\n");
        return;
    }
    
    printf("Statement type: %s\n", stmt_type_to_string(stmt->type));
    
    switch (stmt->type) {
        case STMT_SELECT:
            printf("SELECT List:\n");
            print_expression(stmt->data.select.select_list, 1);
            
            if (stmt->data.select.from_list) {
                printf("FROM:\n");
                table_ref_t* table = stmt->data.select.from_list; 
                bool is_first = true;
                while (table) {
                    if (is_first) {
                        printf("  table: %s\n", table->table_name ? table->table_name : "NULL");
                        if (table->alias) {
                            printf("  alias: %s\n", table->alias);
                        }
                        is_first = false;
                    } else {
                        // This is a joined table
                        const char* join_type_str = "UNKNOWN";
                        if (table->join_type == TOKEN_INNER) {
                            join_type_str = "INNER JOIN";
                        } else if (table->join_type == TOKEN_JOIN) {
                            join_type_str = "JOIN";
                        }
                        
                        printf("  %s: %s\n", join_type_str, table->table_name ? table->table_name : "NULL");
                        if (table->alias) {
                            printf("    alias: %s\n", table->alias);
                        }
                        if (table->join_condition) {
                            printf("    ON condition:\n");
                            print_expression(table->join_condition, 6);
                        }
                    }
                    table = table->next;
                }
            }
            
            if (stmt->data.select.where_clause) {
                printf("WHERE:\n");
                print_expression(stmt->data.select.where_clause, 1);
            }
            
            if (stmt->data.select.order_by) {
                printf("ORDER BY:\n");
                print_expression(stmt->data.select.order_by, 1);
            }
            
            if (stmt->data.select.limit > 0) {
                printf("LIMIT: %u\n", stmt->data.select.limit);
            }
            
            if (stmt->data.select.offset > 0) {
                printf("OFFSET: %u\n", stmt->data.select.offset);
            }
            break;
            
        case STMT_UPDATE:
            printf("UPDATE table: %s\n", stmt->data.update.table_name ? stmt->data.update.table_name : "NULL");
            printf("SET clauses (%u):\n", stmt->data.update.assignment_count);
            for (uint32_t i = 0; i < stmt->data.update.assignment_count; i++) {
                printf("  Assignment[%u]:\n", i);
                print_expression(stmt->data.update.assignments[i], 2);
            }
            if (stmt->data.update.where_clause) {
                printf("WHERE:\n");
                print_expression(stmt->data.update.where_clause, 1);
            }
            break;
            
        case STMT_DELETE:
            printf("DELETE FROM table: %s\n", stmt->data.delete.table_name ? stmt->data.delete.table_name : "NULL");
            if (stmt->data.delete.where_clause) {
                printf("WHERE:\n");
                print_expression(stmt->data.delete.where_clause, 1);
            }
            break;
            
        default:
            printf("Statement details not implemented for this type\n");
            break;
    }
}

// Test cases
static void test_lexer() {
    printf("\n=== Testing Lexer ===\n");
    
    const char* test_sql = "SELECT id, name FROM users WHERE age > 18";
    lexer_t* lexer = lexer_create(test_sql);
    
    if (!lexer) {
        printf("Failed to create lexer\n");
        return;
    }
    
    printf("Input: %s\n", test_sql);
    printf("Tokens:\n");
    
    token_t* token;
    while ((token = lexer_next_token(lexer)) != NULL && token->type != TOKEN_EOF) {
        printf("  %s", token_type_to_string(token->type));
        if (token->value) {
            printf(": '%s'", token->value);
        }
        printf("\n");
        
        if (lexer->error_message) {
            printf("  ERROR: %s\n", lexer->error_message);
            break;
        }
    }
    
    if (token && token->type == TOKEN_EOF) {
        printf("  EOF\n");
    }
    
    lexer_destroy(lexer);
}

static void test_simple_select() {
    printf("\n=== Testing Simple SELECT ===\n");
    
    const char* test_sql = "SELECT name FROM users";
    printf("Input: %s\n", test_sql);
    
    parser_t* parser = parser_create(test_sql);
    if (!parser) {
        printf("Failed to create parser\n");
        return;
    }
    
    statement_t* stmt = parser_parse_statement(parser);
    
    if (parser_has_error(parser)) {
        printf("Parse error: %s\n", parser_get_error(parser));
    } else if (stmt) {
        printf("Parse successful:\n");
        print_statement(stmt);
        statement_destroy(stmt);
    } else {
        printf("No statement parsed\n");
    }
    
    parser_destroy(parser);
}

static void test_select_with_where() {
    printf("\n=== Testing SELECT with WHERE ===\n");
    
    const char* test_sql = "SELECT * FROM users WHERE age > 18";
    printf("Input: %s\n", test_sql);
    
    parser_t* parser = parser_create(test_sql);
    if (!parser) {
        printf("Failed to create parser\n");
        return;
    }
    
    statement_t* stmt = parser_parse_statement(parser);
    
    if (parser_has_error(parser)) {
        printf("Parse error: %s\n", parser_get_error(parser));
    } else if (stmt) {
        printf("Parse successful:\n");
        print_statement(stmt);
        statement_destroy(stmt);
    } else {
        printf("No statement parsed\n");
    }
    
    parser_destroy(parser);
}

static void test_expression_parsing() {
    printf("\n=== Testing Expression Parsing ===\n");
    
    const char* test_expressions[] = {
        "age > 18",
        "name = 'john'",
        "score >= 90 AND grade = 'A'",
        "price * quantity",
        "NOT active",
        "table.column",
        NULL
    };
    
    for (int i = 0; test_expressions[i] != NULL; i++) {
        printf("\nExpression: %s\n", test_expressions[i]);
        
        parser_t* parser = parser_create(test_expressions[i]);
        if (!parser) {
            printf("Failed to create parser\n");
            continue;
        }
        
        expression_t* expr = parser_parse_expression(parser);
        
        if (parser_has_error(parser)) {
            printf("Parse error: %s\n", parser_get_error(parser));
        } else if (expr) {
            printf("Parse successful:\n");
            print_expression(expr, 0);
            expression_destroy(expr);
        } else {
            printf("No expression parsed\n");
        }
        
        parser_destroy(parser);
    }
}

static void test_error_handling() {
    printf("\n=== Testing Error Handling ===\n");
    
    const char* invalid_sql[] = {
        "SELECT FROM",           // Missing select list
        "SELECT name users",     // Missing FROM keyword
        "SELECT name FROM",      // Missing table name
        "SELECT name FROM users WHERE", // Missing WHERE condition
        "SELECT name FROM users WHERE age >", // Incomplete expression
        NULL
    };
    
    for (int i = 0; invalid_sql[i] != NULL; i++) {
        printf("\nInvalid SQL: %s\n", invalid_sql[i]);
        
        parser_t* parser = parser_create(invalid_sql[i]);
        if (!parser) {
            printf("Failed to create parser\n");
            continue;
        }
        
        statement_t* stmt = parser_parse_statement(parser);
        
        if (parser_has_error(parser)) {
            printf("Expected error: %s\n", parser_get_error(parser));
        } else {
            printf("Unexpected success\n");
        }
        
        if (stmt) {
            statement_destroy(stmt);
        }
        
        parser_destroy(parser);
    }
}

static void test_multi_column_select() {
    printf("\\n=== Testing Multi-Column SELECT ===\\n");
    
    const char* test_queries[] = {
        "SELECT id, name FROM users",
        "SELECT id, name, age FROM users WHERE active = 1",
        "SELECT count, total FROM stats",
        "SELECT user_id, order_date, amount FROM orders",
        NULL
    };
    
    for (int i = 0; test_queries[i] != NULL; i++) {
        printf("\\nQuery: %s\\n", test_queries[i]);
        
        parser_t* parser = parser_create(test_queries[i]);
        if (!parser) {
            printf("Failed to create parser\\n");
            continue;
        }
        
        statement_t* stmt = parser_parse_statement(parser);
        
        if (parser_has_error(parser)) {
            printf("Parse error: %s\\n", parser_get_error(parser));
        } else if (stmt) {
            printf("Parse successful:\\n");
            print_statement(stmt);
            statement_destroy(stmt);
        } else {
            printf("No statement parsed\\n");
        }
        
        parser_destroy(parser);
    }
}

static void test_update_statement() {
    printf("\n=== Testing UPDATE Statement ===\n");
    
    const char* test_queries[] = {
        "UPDATE users SET name = 'John' WHERE id = 1",
        "UPDATE products SET price = 29.99, stock = 100",
        "UPDATE customers SET email = 'new@example.com', phone = '555-1234' WHERE active = true"
    };
    
    for (size_t i = 0; i < sizeof(test_queries) / sizeof(test_queries[0]); i++) {
        printf("\nTest %zu: %s\n", i + 1, test_queries[i]);
        
        parser_t* parser = parser_create(test_queries[i]);
        if (!parser) {
            printf("Failed to create parser\n");
            continue;
        }
        
        statement_t* stmt = parser_parse_statement(parser);
        
        if (parser_has_error(parser)) {
            printf("Parse error: %s\n", parser_get_error(parser));
        } else if (stmt) {
            printf("Parse successful:\n");
            print_statement(stmt);
            statement_destroy(stmt);
        } else {
            printf("No statement parsed\n");
        }
        
        parser_destroy(parser);
    }
}

static void test_delete_statement() {
    printf("\n=== Testing DELETE Statement ===\n");
    
    const char* test_queries[] = {
        "DELETE FROM users WHERE id = 1",
        "DELETE FROM products",
        "DELETE FROM orders WHERE created_date < '2023-01-01'"
    };
    
    for (size_t i = 0; i < sizeof(test_queries) / sizeof(test_queries[0]); i++) {
        printf("\nTest %zu: %s\n", i + 1, test_queries[i]);
        
        parser_t* parser = parser_create(test_queries[i]);
        if (!parser) {
            printf("Failed to create parser\n");
            continue;
        }
        
        statement_t* stmt = parser_parse_statement(parser);
        
        if (parser_has_error(parser)) {
            printf("Parse error: %s\n", parser_get_error(parser));
        } else if (stmt) {
            printf("Parse successful:\n");
            print_statement(stmt);
            statement_destroy(stmt);
        } else {
            printf("No statement parsed\n");
        }
        
        parser_destroy(parser);
    }
}

int main() {
    printf("SQL Parser Test Suite\n");
    printf("====================\n");
    
    test_lexer();
    test_simple_select();
    test_select_with_where();
    test_multi_column_select();
    test_expression_parsing();
    test_error_handling();
    test_update_statement();
    test_delete_statement();
    
    printf("\n=== All Tests Completed ===\n");
    return 0;
}